<template>
  <div>
    <div style="display: flex; align-items: center">
      <el-input v-model="fileText" style="width: 100%" placeholder="选择文件上传" @change="fileTextChange">
        <el-button slot="append" @click="showUploader">...</el-button>
      </el-input>

      <common-mini-dialog :add="uploaderVisible" title="上传文件" width="60%" :showFooter="true"
                          :appendToBody="false" @closeMiniDialog="closeMiniDialog" @sureMini="closeMiniDialog ">
        <template #content>
          <uploader
            ref="uploader"
            :options="options"
            :autoStart="false"
            :file-status-text="fileStatusText"
            @file-added="onFileAdded"
            @file-success="onFileSuccess"
            @file-error="onFileError"
            @file-progress="onFileProgress"
            @file-removed="removeFile"
            class="uploader-example"
          >
            <uploader-unsupport></uploader-unsupport>
            <uploader-drop>
              <p>拖动文件到这里上传</p>
              <div style="display: flex">
                <div :style="fileUP">
                  <uploader-btn :attrs="attrs">选择文件</uploader-btn>
                </div>
                <div :style="dicUP">
                  <uploader-btn :directory="true">选择文件夹</uploader-btn>
                </div>
              </div>
            </uploader-drop>
            <!-- uploader-list可自定义样式 -->
            <!-- <uploader-list></uploader-list> -->
            <uploader-list>
              <div class="file-panel" :class="{ collapse: collapse }">
                <div class="file-title">
                  <p class="file-list-title">文件列表</p>
                  <div class="operate">
                    <el-button type="text" @click="operate" :title="collapse ? '折叠' : '展开'">
                      <i class="icon" :class="collapse ? 'el-icon-caret-bottom' : 'el-icon-caret-top'"></i>
                    </el-button>
                    <!--                    <el-button type="text" @click="close" title="关闭">-->
                    <!--                      <i class="icon el-icon-close"></i>-->
                    <!--                    </el-button>-->
                  </div>
                </div>

                <ul class="file-list" :class=" collapse ? 'uploader-list-ul-show' : 'uploader-list-ul-hidden'">
                  <li v-for="(file,index) in uploadFileList" :key="file.id">
                    <uploader-file :class="'file_' + file.id" ref="files" :file="file" :list="true"></uploader-file>
                  </li>
                  <div class="no-file" v-if="!uploadFileList.length">
                    <i class="icon icon-empty-file"></i> 暂无待上传文件
                  </div>
                </ul>
              </div>
            </uploader-list>
            <!--          <span>下载</span>-->
          </uploader>
        </template>

      </common-mini-dialog>
    </div>
  </div>
</template>
<script>
import SparkMD5 from 'spark-md5'
import baseComp from './baseComp'

const FILE_UPLOAD_ID_KEY = "file_upload_id";
// 分片大小，20MB
const CHUNK_SIZE = 20 * 1024 * 1024;
let _this = null
export default {
  name: "fileUpload",
  components: {},
  model: {
    prop: 'fileText',
    event: 'fileChange'
  },
  extends: baseComp,
  props: {
    myData: {
      type: Object,
      default: () => {
      },

    },
    fileText: {
      type: [String, Number, Array],
      default: () => {
      },
    },
  },
  data() {
    return {
      id: 'myFileUpload',
      uploaderVisible: false,
      attrs: {
        // 接受的文件类型 根据实际需要
        accept: [".zip", ".rar"]
      },
      // 配置变量
      isUpDocument: '',
      isUpDocumentFile: '',
      isMultifile: '',
      isFileFragmentation: '',
      isFileSize: '',
      isFileSizeText: '',
      address: '',
      interfacePath: '',
      // 样式设置
      fileUP: {
        display: 'block'
      },
      dicUP: {
        display: 'block'
      },
      // 参数
      options: {
        // 上传地址
        target: '',
        // 是否开启服务器分片校验。默认为 true
        testChunks: true,
        // 真正上传的时候使用的 HTTP 方法,默认 POST
        uploadMethod: "post",
        // 分片大小
        chunkSize: CHUNK_SIZE,
        // 并发上传数，默认为 3
        simultaneousUploads: 3,
        singleFile: true,
        headers:{},
        /**
         * 判断分片是否上传，秒传和断点续传基于此方法
         * 这里根据实际业务来 用来判断哪些片已经上传过了 不用再重复上传了 [这里可以用来写断点续传！！！]
         */
        checkChunkUploadedByResponse: (chunk, message) => {
          try {
            // message是后台返回
            let messageObj = JSON.parse(message);
            let dataObj = messageObj.data;
            if (dataObj.uploaded !== undefined) {
              return dataObj.uploaded;
            }
            // 判断文件或分片是否已上传，已上传返回 true
            // 这里的 uploadedChunks 是后台返回]
            return (dataObj.uploadedChunks || []).indexOf(chunk.offset + 1) >= 0;
          } catch (e) {

          }
        },
        parseTimeRemaining: function (timeRemaining, parsedTimeRemaining) {
          //格式化时间
          return parsedTimeRemaining
            .replace(/\syears?/, "年")
            .replace(/\days?/, "天")
            .replace(/\shours?/, "小时")
            .replace(/\sminutes?/, "分钟")
            .replace(/\sseconds?/, "秒");
        },
        query: function (file, res, status) {
          let addressData = _this.address;
          return {
            "address": addressData,
          }
        },

      },
      // 修改上传状态
      fileStatusTextObj: {
        success: "上传成功",
        error: "上传错误",
        uploading: "正在上传",
        paused: "停止上传",
        waiting: "等待中",
      },
      uploadIdInfo: null,
      uploadFileList: [],
      fileChunkList: [],
      collapse: true,
    };
  },
  created() {
  },
  mounted() {
    _this = this
  },
  beforeDestroy() {
  },
  watch: {
    file: {
      handler(v) {
      },
      deep: true,
      immediate: true
    },
    myData: {
      handler(val) {
        this.initData()
      },
      deep: true,
      immediate: true
    }
  },
  methods: {
    /**
     * 删除文件
     */
    removeFile(file) {
      let fileIndex = this.uploadFileList.findIndex(item => item.name == file.name);
      this.uploadFileList.splice(fileIndex, 1);
    },
    /**
     * 展示关闭上传组件
     */
    showUploader() {
      this.uploaderVisible = true;
    },
    closeMiniDialog() {
      this.uploaderVisible = false;
    },
    initData() {
      let obj = this.myData
      this.address = obj.address;//地址
      this.isUpDocument = obj.isUpDocument//是否上传文件
      this.isUpDocumentFile = obj.isUpDocumentFile//是否上传文件夹
      this.attrs.accept = obj.isUpDocumentFileText//文件格式限制

      this.isMultifile = obj.isMultifile//是否多文件上传
      this.isFileFragmentation = obj.isFileFragmentation//是否启用分片
      this.isFileSize = obj.isFileSize//是否启动文件大小限制
      this.interfacePath = obj.interfacePath //文件上传接口路径
      //文件上传接口
      this.options.target = this.interfacePath
      // token
      this.options.headers = {token: localStorage.getItem("token")}
      //是否上传文件
      if (this.isUpDocument == false) {
        this.fileUP.display = 'none'
      }
      //是否上传文件夹
      if (this.isUpDocumentFile == false) {
        this.dicUP.display = 'none'
      }
      if (this.isMultifile == true) {
        this.options.singleFile = false;
        // obj.isMultifileText//多文件上传大小
      }
      if (this.isFileFragmentation == true) {
        this.options.chunkSize = obj.isFileFragmentationText//分片大小设置
      }
      if (this.isFileSize == true) {
        this.isFileSizeText = obj.isFileSizeText//文件大小限制
      }
    },

    /**
     * 添加文件函数
     */
    onFileAdded(file, event) {
      // 判断是否为空 为空执行
      // 不为空判断大小 大于不执行 小于执行
      if (this.isFileSizeText != null || this.isFileSizeText > file.size) {
        this.uploadFileList.push(file);
        console.log("file :>> ", file);
        // 有时 fileType为空，需截取字符
        console.log("文件类型：" + file.fileType);
        // 文件大小
        console.log("文件大小：" + file.size + "B");
        // 1. todo 判断文件类型是否允许上传
        // 2. 计算文件 MD5 并请求后台判断是否已上传，是则取消上传
        console.log("校验MD5");
        this.getFileMD5(file, (md5) => {
          if (md5 != "") {
            // 修改文件唯一标识
            file.uniqueIdentifier = md5;
            // 请求后台判断是否上传
            // 恢复上传
            file.resume();
            console.log(file)
          }
        });
      }
    },
    /**
     * 文件上传成功函数
     */
    onFileSuccess(rootFile, file, response, chunk) {
      this.fileText = JSON.parse(response)['data']
      // this.fileText =  this.address + "/" + file.name
      this.$emit('fileChange', this.fileText);
      console.log("上传成功");
    },

    fileTextChange() {
      this.$emit('fileChange', this.fileText);
    },

    /**
     * 文件上传失败函数
     */
    onFileError(rootFile, file, message, chunk) {
      console.log("上传出错：" + message);
    },
    /**
     * 文件上传进度函数
     */
    onFileProgress(rootFile, file, chunk) {
      console.log(`当前进度：${Math.ceil(file._prevProgress * 100)}%`);
    },

    // 计算文件的MD5值
    getFileMD5(file, callback) {
      let spark = new SparkMD5.ArrayBuffer();
      let fileReader = new FileReader();
      //获取文件分片对象（注意它的兼容性，在不同浏览器的写法不同）
      let blobSlice =
        File.prototype.slice ||
        File.prototype.mozSlice ||
        File.prototype.webkitSlice;
      // 当前分片下标
      let currentChunk = 0;
      // 分片总数(向下取整)
      let chunks = Math.ceil(file.size / CHUNK_SIZE);
      // MD5加密开始时间
      let startTime = new Date().getTime();
      // 暂停上传
      file.pause();
      loadNext();
      // fileReader.readAsArrayBuffer操作会触发onload事件
      fileReader.onload = function (e) {
        // console.log("currentChunk :>> ", currentChunk);
        spark.append(e.target.result);
        if (currentChunk < chunks) {
          currentChunk++;
          loadNext();
        } else {
          // 该文件的md5值
          let md5 = spark.end();
          console.log(
            `MD5计算完毕：${md5}，耗时：${new Date().getTime() - startTime} ms.`
          );
          // 回调传值md5
          callback(md5);
        }
      };
      fileReader.onerror = function () {
        this.$message.error("文件读取错误");
        file.cancel();
      };

      // 加载下一个分片
      function loadNext() {
        const start = currentChunk * CHUNK_SIZE;
        const end =
          start + CHUNK_SIZE >= file.size ? file.size : start + CHUNK_SIZE;
        // 文件分片操作，读取下一分片(fileReader.readAsArrayBuffer操作会触发onload事件)
        fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
      }
    },
    /**
     * 文件上传状态显示函数
     */
    fileStatusText(status, response) {
      if (status === "md5") {
        return "校验MD5";
      } else {
        return this.fileStatusTextObj[status];
      }
    },
    // 文件格式校验
    fileType(file) {

    },

    /**
     * 折叠、展开面板动态切换
     */
    operate() {
      if (this.collapse === false) {
        this.collapse = true;
      } else {
        this.collapse = false;
      }
    },

    /**
     * 关闭折叠面板
     */
    close() {
      this.uploaderPanelShow = false;
    },
  },
};
</script>
<style lang="less" scoped>
.container {
  height: 400px;
  width: 30vw;
}

//.logo {
//  font-family: "Avenir", Helvetica, Arial, sans-serif;
//  -webkit-font-smoothing: antialiased;
//  -moz-osx-font-smoothing: grayscale;
//  text-align: center;
//  color: #2c3e50;
//  margin-top: 60px;
//}
.uploader-example {
  width: 100%;
  //padding: 15px;
  //margin: 40px auto 0;
  font-size: 12px;
  //box-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
}

.uploader-example .uploader-btn {
  margin-right: 4px;
}

.uploader-example .uploader-list {
  max-height: 440px;
  overflow: auto;
  overflow-x: hidden;
  overflow-y: auto;
}

#global-uploader {
  position: fixed;
  z-index: 20;
  right: 15px;
  bottom: 15px;
  width: 550px;
}

.file-panel {
  background-color: #fff;
  border: 1px solid #e2e2e2;
  border-radius: 7px 7px 0 0;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
}

.file-title {
  display: flex;
  height: 60px;
  line-height: 30px;
  padding: 0 15px;
  border-bottom: 1px solid #ddd;
}

.file-title {
  background-color: #e7ecf2;
}

.uploader-file-meta {
  display: none !important;
}

.operate {
  flex: 1;
  text-align: right;
}

.file-list {
  position: relative;
  height: 240px;
  overflow-x: hidden;
  overflow-y: auto;
  background-color: #fff;
  padding: 0px;
  margin: 0 auto;
  transition: all 0.5s;
}

.uploader-file-size {
  width: 15% !important;
}

.uploader-file-status {
  width: 32.5% !important;
  text-align: center !important;
}

li {
  background-color: #fff;
  list-style-type: none;
}

.no-file {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 16px;
}

/* 隐藏上传按钮 */
.global-uploader-btn {
  display: none !important;
  clip: rect(0, 0, 0, 0);
  /* width: 100px;
  height: 50px; */
}

.file-list-title {
  /*line-height: 10px;*/
  font-size: 16px;
}

.uploader-file-name {
  width: 36% !important;
}

.uploader-file-actions {
  float: right !important;
}

.uploader-list-ul-hidden {
  height: 0px;

}

</style>


